'use strict';

const { MongoClient, ObjectId } = require('mongodb');
const fs = require('fs');
const path = require('path');

/**
 * MongoDB服务，提供MongoDB数据库操作
 */
class MongoDBServer {
  /**
   * 构造函数
   */
  constructor() {
    this._client = null;
    this._db = null;
    this._config = this._loadConfig();
    this._isConnected = false;
  }
  /**
   * 加载MongoDB配置
   * @returns {object} MongoDB配置
   * @private
   */
  _loadConfig() {
    try {
      const baseConfigPath = path.resolve(process.cwd(), 'config/baseConfig.json');
      if (fs.existsSync(baseConfigPath)) {
        const configContent = fs.readFileSync(baseConfigPath, 'utf8');
        const config = JSON.parse(configContent);

        if (config.mongodb) {
          // 设置默认值
          const mongoConfig = {
            host: config.mongodb.host || 'localhost',
            port: config.mongodb.port || 27017,
            database: config.mongodb.database || 'rpcserver'
          };

          // 如果有用户名和密码，添加到配置中
          if (config.mongodb.user && config.mongodb.password) {
            mongoConfig.user = config.mongodb.user;
            mongoConfig.password = config.mongodb.password;
          }

          return mongoConfig;
        }
      }
    } catch (error) {
      console.error('[MongoDB] 加载MongoDB配置失败:', error);
    }

    // 返回默认配置
    return {
      host: 'localhost',
      port: 27017,
      database: 'rpcserver'
    };
  }

  /**
   * 初始化服务
   */
  async init() {
    console.log(`[MongoDB] 服务初始化中...`);
    
    // 1. 首先连接数据库
    const connected = await this.connect();
    if (!connected) {
      throw new Error('MongoDB连接失败');
    }
  }

  /**
   * 构建MongoDB连接URL
   * @param {object} config 配置信息
   * @returns {string} 连接URL
   * @private
   */
  _buildConnectionUrl(config) {
    let url = 'mongodb://';

    // 添加认证信息
    if (config.user && config.password) {
      url += `${encodeURIComponent(config.user)}:${encodeURIComponent(config.password)}@`;
    }

    // 添加主机和端口
    url += `${config.host}:${config.port}`;

    // 添加数据库名
    url += `/${config.database}`;

    return url;
  }

  /**
   * 连接到MongoDB数据库
   * @param {object} [options] 可选的配置信息，覆盖默认配置
   * @returns {Promise<boolean>} 是否连接成功
   */
  async connect(options) {
    try {
      // 如果已经连接，先断开
      if (this._isConnected) {
        await this.disconnect();
      }

      // 合并配置
      if (options) {
        this._config = { ...this._config, ...options };
      }

      // 构建连接URL
      const url = this._buildConnectionUrl(this._config);

      // 创建MongoDB客户端
      this._client = new MongoClient(url, {
        useNewUrlParser: true,
        useUnifiedTopology: true
      });

      // 连接到MongoDB
      await this._client.connect();
      this._db = this._client.db(this._config.database);
      this._isConnected = true;

      console.log(`[MongoDB] 已连接到MongoDB服务器: ${this._config.host}:${this._config.port}`);
      return true;
    } catch (error) {
      console.error(`[MongoDB] 连接错误:`, error);
      this._isConnected = false;
      return false;
    }
  }

  /**
   * 断开MongoDB连接
   * @returns {Promise<boolean>} 是否断开成功
   */
  async disconnect() {
    try {
      if (this._client) {
        await this._client.close();
        this._client = null;
        this._db = null;
      }
      this._isConnected = false;
      console.log(`[MongoDB] 连接已关闭`);
      return true;
    } catch (error) {
      console.error(`[MongoDB] 断开连接错误:`, error);
      return false;
    }
  }

  /**
   * 检查连接状态
   * @private
   */
  _checkConnection() {
    if (!this._isConnected || !this._client || !this._db) {
      throw new Error('MongoDB未连接，请先调用connect方法');
    }
  }

  /**
   * 获取集合
   * @param {string} collectionName 集合名称
   * @returns {Collection} 集合对象
   * @private
   */
  _getCollection(collectionName) {
    this._checkConnection();
    return this._db.collection(collectionName);
  }

  /**
   * 获取集合
   * @param {string} collectionName 集合名称
   * @returns {Collection} 集合对象
   */
  collection(collectionName) {
    this._checkConnection();
    return this._db.collection(collectionName);
  }

  /**
   * 查找单个文档
   * @param {string} collection 集合名称
   * @param {object} query 查询条件
   * @param {object} [options] 查询选项
   * @returns {Promise<object|null>} 查询结果
   */
  async findOne(collection, query, options = {}) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] FIND_ONE ${collection}`, query);
      }

      const coll = this._getCollection(collection);
      return await coll.findOne(this._processQuery(query), options);
    } catch (error) {
      console.error(`[MongoDB] FIND_ONE ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 查找多个文档
   * @param {string} collection 集合名称
   * @param {object} query 查询条件
   * @param {object} [options] 查询选项
   * @returns {Promise<Array>} 查询结果
   */
  async find(collection, query, options = {}) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] FIND ${collection}`, query);
      }

      const coll = this._getCollection(collection);
      return await coll.find(this._processQuery(query), options).toArray();
    } catch (error) {
      console.error(`[MongoDB] FIND ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 计数
   * @param {string} collection 集合名称
   * @param {object} query 查询条件
   * @returns {Promise<number>} 文档数量
   */
  async count(collection, query) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] COUNT ${collection}`, query);
      }

      const coll = this._getCollection(collection);
      return await coll.countDocuments(this._processQuery(query));
    } catch (error) {
      console.error(`[MongoDB] COUNT ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 插入单个文档
   * @param {string} collection 集合名称
   * @param {object} document 文档
   * @returns {Promise<object>} 插入结果
   */
  async insertOne(collection, document) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] INSERT_ONE ${collection}`, document);
      }

      const coll = this._getCollection(collection);
      const result = await coll.insertOne(document);
      return {
        acknowledged: result.acknowledged,
        insertedId: result.insertedId.toString()
      };
    } catch (error) {
      console.error(`[MongoDB] INSERT_ONE ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 插入多个文档
   * @param {string} collection 集合名称
   * @param {Array} documents 文档数组
   * @returns {Promise<object>} 插入结果
   */
  async insertMany(collection, documents) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] INSERT_MANY ${collection}`, documents.length);
      }

      const coll = this._getCollection(collection);
      const result = await coll.insertMany(documents);
      return {
        acknowledged: result.acknowledged,
        insertedCount: result.insertedCount,
        insertedIds: Object.values(result.insertedIds).map(id => id.toString())
      };
    } catch (error) {
      console.error(`[MongoDB] INSERT_MANY ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 更新单个文档
   * @param {string} collection 集合名称
   * @param {object} filter 过滤条件
   * @param {object} update 更新内容
   * @param {object} [options] 更新选项
   * @returns {Promise<object>} 更新结果
   */
  async updateOne(collection, filter, update, options = {}) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] UPDATE_ONE ${collection}`, filter, update);
      }

      const coll = this._getCollection(collection);

      // 如果update不包含操作符，则自动添加$set
      if (!update.$set && !update.$unset && !update.$inc && !update.$push && !update.$pull) {
        update = { $set: update };
      }

      const result = await coll.updateOne(this._processQuery(filter), update, options);
      return {
        acknowledged: result.acknowledged,
        matchedCount: result.matchedCount,
        modifiedCount: result.modifiedCount,
        upsertedCount: result.upsertedCount,
        upsertedId: result.upsertedId ? result.upsertedId.toString() : null
      };
    } catch (error) {
      console.error(`[MongoDB] UPDATE_ONE ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 更新多个文档
   * @param {string} collection 集合名称
   * @param {object} filter 过滤条件
   * @param {object} update 更新内容
   * @param {object} [options] 更新选项
   * @returns {Promise<object>} 更新结果
   */
  async updateMany(collection, filter, update, options = {}) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] UPDATE_MANY ${collection}`, filter, update);
      }

      const coll = this._getCollection(collection);

      // 如果update不包含操作符，则自动添加$set
      if (!update.$set && !update.$unset && !update.$inc && !update.$push && !update.$pull) {
        update = { $set: update };
      }

      const result = await coll.updateMany(this._processQuery(filter), update, options);
      return {
        acknowledged: result.acknowledged,
        matchedCount: result.matchedCount,
        modifiedCount: result.modifiedCount,
        upsertedCount: result.upsertedCount,
        upsertedId: result.upsertedId ? result.upsertedId.toString() : null
      };
    } catch (error) {
      console.error(`[MongoDB] UPDATE_MANY ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 删除单个文档
   * @param {string} collection 集合名称
   * @param {object} filter 过滤条件
   * @returns {Promise<object>} 删除结果
   */
  async deleteOne(collection, filter) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] DELETE_ONE ${collection}`, filter);
      }

      const coll = this._getCollection(collection);
      const result = await coll.deleteOne(this._processQuery(filter));
      return {
        acknowledged: result.acknowledged,
        deletedCount: result.deletedCount
      };
    } catch (error) {
      console.error(`[MongoDB] DELETE_ONE ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 删除多个文档
   * @param {string} collection 集合名称
   * @param {object} filter 过滤条件
   * @returns {Promise<object>} 删除结果
   */
  async deleteMany(collection, filter) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] DELETE_MANY ${collection}`, filter);
      }

      const coll = this._getCollection(collection);
      const result = await coll.deleteMany(this._processQuery(filter));
      return {
        acknowledged: result.acknowledged,
        deletedCount: result.deletedCount
      };
    } catch (error) {
      console.error(`[MongoDB] DELETE_MANY ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 聚合查询
   * @param {string} collection 集合名称
   * @param {Array} pipeline 聚合管道
   * @returns {Promise<Array>} 聚合结果
   */
  async aggregate(collection, pipeline) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] AGGREGATE ${collection}`, pipeline);
      }

      const coll = this._getCollection(collection);
      return await coll.aggregate(pipeline).toArray();
    } catch (error) {
      console.error(`[MongoDB] AGGREGATE ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 创建索引
   * @param {string} collection 集合名称
   * @param {object} keys 索引键
   * @param {object} [options] 索引选项
   * @returns {Promise<string>} 索引名称
   */
  async createIndex(collection, keys, options = {}) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] CREATE_INDEX ${collection}`, keys, options);
      }

      const coll = this._getCollection(collection);
      return await coll.createIndex(keys, options);
    } catch (error) {
      console.error(`[MongoDB] CREATE_INDEX ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 删除索引
   * @param {string} collection 集合名称
   * @param {string} indexName 索引名称
   * @returns {Promise<object>} 删除结果
   */
  async dropIndex(collection, indexName) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] DROP_INDEX ${collection} ${indexName}`);
      }

      const coll = this._getCollection(collection);
      return await coll.dropIndex(indexName);
    } catch (error) {
      console.error(`[MongoDB] DROP_INDEX ${collection} 错误:`, error);
      throw error;
    }
  }

  /**
   * 列出所有集合
   * @returns {Promise<Array>} 集合列表
   */
  async listCollections() {
    try {
      this._checkConnection();
      const collections = await this._db.listCollections().toArray();
      return collections.map(c => c.name);
    } catch (error) {
      console.error(`[MongoDB] LIST_COLLECTIONS 错误:`, error);
      throw error;
    }
  }

  /**
   * 创建集合
   * @param {string} name 集合名称
   * @param {object} [options] 创建选项
   * @returns {Promise<object>} 创建结果
   */
  async createCollection(name, options = {}) {
    try {
      this._checkConnection();
      if (this.isDebug) {
        console.debug(`[MongoDB] CREATE_COLLECTION ${name}`);
      }

      await this._db.createCollection(name, options);
      return { success: true, name };
    } catch (error) {
      console.error(`[MongoDB] CREATE_COLLECTION ${name} 错误:`, error);
      throw error;
    }
  }

  /**
   * 删除集合
   * @param {string} name 集合名称
   * @returns {Promise<boolean>} 是否成功
   */
  async dropCollection(name) {
    try {
      this._checkConnection();
      if (this.isDebug) {
        console.debug(`[MongoDB] DROP_COLLECTION ${name}`);
      }

      const result = await this._db.dropCollection(name);
      return result;
    } catch (error) {
      console.error(`[MongoDB] DROP_COLLECTION ${name} 错误:`, error);
      throw error;
    }
  }

  /**
   * 处理查询对象，转换特殊字段
   * @param {object} query 查询对象
   * @returns {object} 处理后的查询对象
   * @private
   */
  _processQuery(query) {
    if (!query || typeof query !== 'object') {
      return query;
    }

    const result = {};

    // 处理查询对象中的每个字段
    for (const [key, value] of Object.entries(query)) {
      // 处理_id字段，将字符串转换为ObjectId
      if (key === '_id' && typeof value === 'string') {
        try {
          result[key] = new ObjectId(value);
        } catch (e) {
          result[key] = value;
        }
      }
      // 处理嵌套对象
      else if (value && typeof value === 'object' && !Array.isArray(value)) {
        // 检查是否为操作符对象
        if (Object.keys(value).some(k => k.startsWith('$'))) {
          // 处理操作符对象中的特殊字段
          const processedOps = {};
          for (const [opKey, opValue] of Object.entries(value)) {
            if (opKey === '$in' || opKey === '$nin') {
              // 处理$in/$nin数组中的_id
              if (key === '_id' && Array.isArray(opValue)) {
                processedOps[opKey] = opValue.map(id => {
                  if (typeof id === 'string') {
                    try {
                      return new ObjectId(id);
                    } catch (e) {
                      return id;
                    }
                  }
                  return id;
                });
              } else {
                processedOps[opKey] = opValue;
              }
            } else {
              processedOps[opKey] = opValue;
            }
          }
          result[key] = processedOps;
        } else {
          // 递归处理嵌套对象
          result[key] = this._processQuery(value);
        }
      } else {
        result[key] = value;
      }
    }

    return result;
  }

  /**
   * 查找最近的商家
   * @param {number} longitude 经度
   * @param {number} latitude 纬度
   * @param {number} maxDistance 最大距离（米）
   * @param {number} limit 返回数量限制
   * @param {object} [filters] 额外的过滤条件
   * @param {object} [options] 查询选项
   * @returns {Promise<Array>} 商家列表
   */
  async findNearbyStores(longitude, latitude, maxDistance = 5000, limit = 30, filters = {}, options = {}) {
    try {
      if (this.isDebug) {
        console.debug(`[MongoDB] FIND_NEARBY_STORES`, { longitude, latitude, maxDistance, limit, filters });
      }

      const coll = this._getCollection('store');

      // 构建地理位置查询
      const query = {
        coordinates: {
          $near: {
            $geometry: {
              type: 'Point',
              coordinates: [longitude, latitude]
            },
            $maxDistance: maxDistance
          }
        },
        ...filters
      };

      // 设置默认选项
      const defaultOptions = {
        limit,
        projection: {
          _id: 1,
          pid: 1,
          merchant_name: 1,
          coordinates: 1,
          rating: 1,
          businessStatus: 1,
          address: 1,
          business_district: 1,
          main_category: 1,
          averageCost: 1,
          merchant_image: 1
        }
      };

      // 合并选项
      const finalOptions = { ...defaultOptions, ...options };

      // 执行查询
      const stores = await coll.find(query, finalOptions).toArray();

      // 计算距离并添加到结果中
      return stores.map(store => {
        const distance = this._calculateDistance(
          longitude,
          latitude,
          store.coordinates[0],
          store.coordinates[1]
        );
        return {
          ...store,
          distance: Math.round(distance) // 距离（米）
        };
      });
    } catch (error) {
      console.error(`[MongoDB] FIND_NEARBY_STORES 错误:`, error);
      throw error;
    }
  }

  /**
   * 计算两点之间的距离（米）
   * @param {number} lon1 起点经度
   * @param {number} lat1 起点纬度
   * @param {number} lon2 终点经度
   * @param {number} lat2 终点纬度
   * @returns {number} 距离（米）
   * @private
   */
  _calculateDistance(lon1, lat1, lon2, lat2) {
    const R = 6371000; // 地球半径（米）
    const φ1 = lat1 * Math.PI / 180;
    const φ2 = lat2 * Math.PI / 180;
    const Δφ = (lat2 - lat1) * Math.PI / 180;
    const Δλ = (lon2 - lon1) * Math.PI / 180;

    const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
      Math.cos(φ1) * Math.cos(φ2) *
      Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return R * c;
  }
}

module.exports = MongoDBServer;